package com.ctrun.view.indicatorview;

import android.animation.ArgbEvaluator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.ViewPager2;

import com.ctrun.view.indicatorview.banner.LoopAdapter;

/**
 * @author ctrun on 2022/7/25.
 * 轮播图指示器
 */
public class IndicatorView extends View {
    private static final String TAG = "IndicatorView";

    public IndicatorView(Context context) {
        this(context, null);
    }

    public IndicatorView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public IndicatorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private final RecyclerViewDataObserver mDataObserver = new RecyclerViewDataObserver();
    private ViewPager2 mViewPager2;
    @SuppressWarnings("rawtypes")
    private LoopAdapter mLoopAdapter;

    private ArgbEvaluator mArgbEvaluator;
    /** 指示器的颜色 */
    private int mNormalColor;
    /** 选中指示器的颜色 */
    private int mSelectedColor;

    private int mItemCount;
    /** 指示器的宽度 */
    private int mItemWidth;
    /** 选中指示器的宽度 */
    private int mSelectedItemWidth;
    /** 两指示器之间的间距 */
    private int mItemSpace;
    /** 指示器圆角大小 */
    private int mItemRoundSize;
    private int mWidth;
    private int mHeight;
    private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private void init(final Context context, AttributeSet attrs) {
        int itemHeight;
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.IndicatorView, 0, 0);
        try {
            mItemWidth = a.getDimensionPixelSize(R.styleable.IndicatorView_item_width, dipsToPixels(7));
            itemHeight = a.getDimensionPixelSize(R.styleable.IndicatorView_item_height, dipsToPixels(5));
            mSelectedItemWidth = a.getDimensionPixelSize(R.styleable.IndicatorView_selected_item_width, dipsToPixels(15));
            mItemSpace = a.getDimensionPixelSize(R.styleable.IndicatorView_item_space, dipsToPixels(3));
            mItemRoundSize = a.getDimensionPixelSize(R.styleable.IndicatorView_item_round_size, 0);
            mNormalColor = a.getColor(R.styleable.IndicatorView_indicator_color, ContextCompat.getColor(context, R.color.indicator_color));
            mSelectedColor = a.getColor(R.styleable.IndicatorView_selected_indicator_color, ContextCompat.getColor(context, R.color.selected_indicator_color));
        } finally {
            a.recycle();
        }

        mPaint.setColor(mNormalColor);
        mWidth = 0;
        mHeight = itemHeight;
        mArgbEvaluator = new ArgbEvaluator();
    }

    private void setItemCount(int itemCount) {
        mItemCount = itemCount;

        mWidth = calculateWidth();

        if (mItemCount <= 1) {
            setVisibility(GONE);
        } else {
            setVisibility(VISIBLE);
        }

        requestLayout();
    }

    public void attachToViewPager2(ViewPager2 viewPager2) {
        if (mViewPager2 == viewPager2) {
            return;
        }

        if (mViewPager2 != null) {
            mViewPager2.unregisterOnPageChangeCallback(mOnPageChangeCallback);
        }

        if (mLoopAdapter != null) {
            mLoopAdapter.unregisterAdapterDataObserver(mDataObserver);
        }

        mViewPager2 = viewPager2;

        if (mViewPager2 != null) {
            //noinspection rawtypes
            mLoopAdapter = (LoopAdapter) mViewPager2.getAdapter();
            if (mLoopAdapter != null) {
                mLoopAdapter.registerAdapterDataObserver(mDataObserver);
                setItemCount(mLoopAdapter.getRealItemCount());
            } else {
                setItemCount(0);
            }

            mViewPager2.registerOnPageChangeCallback(mOnPageChangeCallback);
        }
    }

    private final ViewPager2.OnPageChangeCallback mOnPageChangeCallback = new ViewPager2.OnPageChangeCallback() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            if (mLoopAdapter != null) {
                int realPosition = mLoopAdapter.getRealPosition(position);
                setProgress(realPosition, 1 - positionOffset);
            }
        }

        @Override
        public void onPageSelected(int position) {
            if (mLoopAdapter != null) {
                int realPosition = mLoopAdapter.getRealPosition(position);
                setProgress(realPosition, 1.f);
            }
        }

    };

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = resolveSize(mWidth, widthMeasureSpec);
        int height = resolveSize(mHeight, heightMeasureSpec);
        setMeasuredDimension(width, height);
    }

    private int calculateWidth() {
        if (mItemCount <= 1) {
            return mSelectedItemWidth;
        }

        return mItemWidth * (mItemCount - 1) + mSelectedItemWidth + mItemSpace * (mItemCount - 1);
    }

    private int mPosition;
    private float mProgress;
    public void setProgress(int position, float progress) {
        mPosition = position;
        mProgress = Math.abs(progress);
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Log.d(TAG, "position: " + mPosition + ",progress: " + mProgress);

        if (mItemCount <= 1) {
            return;
        }

        final int height = getHeight();

        float left = 0;
        float right = 0;

        final float offset;
        if (mPosition == mItemCount-1) {
            offset = (mSelectedItemWidth - mItemWidth) * (1 - mProgress);
        } else {
            offset = 0;
        }

        for (int i = 0; i < mItemCount; i++) {
            if (i < mPosition) {
                if (i == 0) {
                    left = 0;
                    right = mItemWidth + offset;
                } else {
                    left = (mItemWidth + mItemSpace) * i + offset;
                    right = (mItemWidth + mItemSpace) * i + mItemWidth + offset;
                }
            }

            if (i == mPosition) {
                if (mPosition == mItemCount - 1) {
                    left = (mItemWidth + mItemSpace) * i + offset;
                    right = (mItemWidth + mItemSpace) * i + mSelectedItemWidth;
                } else {
                    left = (mItemWidth + mItemSpace) * i;
                    right = (mItemWidth + mItemSpace) * i + mItemWidth + (mSelectedItemWidth - mItemWidth) * mProgress;
                }
            }

            if (i == mPosition + 1) {
                left = (mItemWidth + mItemSpace) * i + (mSelectedItemWidth - mItemWidth) * mProgress;
                right = (mItemWidth + mItemSpace) * i + mSelectedItemWidth;
            }

            if (i > mPosition + 1) {
                left = (mItemWidth + mItemSpace) * (i - 1) + mSelectedItemWidth + mItemSpace + offset;
                right = (mItemWidth + mItemSpace) * i + mSelectedItemWidth + offset;
            }

            if (i == mPosition) {
                int color = (int) mArgbEvaluator.evaluate(mProgress, mNormalColor, mSelectedColor);
                mPaint.setColor(color);
            } else if (i == mPosition + 1) {
                int color = (int) mArgbEvaluator.evaluate(1-mProgress, mNormalColor, mSelectedColor);
                mPaint.setColor(color);
            } else {
                mPaint.setColor(mNormalColor);

                if (i == 0) {
                    if (mPosition == mItemCount - 1) {
                        int color = (int) mArgbEvaluator.evaluate(1-mProgress, mNormalColor, mSelectedColor);
                        mPaint.setColor(color);
                    }
                }
            }

            canvas.drawRoundRect(left, 0, right, height, mItemRoundSize, mItemRoundSize, mPaint);
        }

    }

    private int dipsToPixels(int dips) {
        float scale = getContext().getResources().getDisplayMetrics().density;
        return (int) (dips * scale + 0.5f);
    }


    private class RecyclerViewDataObserver extends RecyclerView.AdapterDataObserver {
        RecyclerViewDataObserver() {}

        @Override
        public void onChanged() {
            setItemCount(mLoopAdapter == null ? 0 : mLoopAdapter.getRealItemCount());
        }

        @Override
        public void onItemRangeChanged(int positionStart, int itemCount) {
            setItemCount(mLoopAdapter == null ? 0 : mLoopAdapter.getRealItemCount());
        }

        @Override
        public void onItemRangeChanged(int positionStart, int itemCount, @Nullable Object payload) {
            setItemCount(mLoopAdapter == null ? 0 : mLoopAdapter.getRealItemCount());
        }

        @Override
        public void onItemRangeInserted(int positionStart, int itemCount) {
            setItemCount(mLoopAdapter == null ? 0 : mLoopAdapter.getRealItemCount());
        }

        @Override
        public void onItemRangeRemoved(int positionStart, int itemCount) {
            setItemCount(mLoopAdapter == null ? 0 : mLoopAdapter.getRealItemCount());
        }

        @Override
        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
            setItemCount(mLoopAdapter == null ? 0 : mLoopAdapter.getRealItemCount());
        }
    }
}
